导航菜单
首页 >  Monaco Editor教程六  > MONACO EDITOR基本使用指南

MONACO EDITOR基本使用指南

目录

MONACO EDITOR基本使用指南

Monaco Editor 是由 Microsoft 开发并开源的一款代码编辑器,它是 Visual Studio Code 的核心编辑器部分。同时还提供了丰富的 API,使得开发者可以根据自己的需求进行定制。Monaco Editor 有着强大的功能且可以满足各种奇葩产品的癖好。

但是由于官方文档过于精简,demo 看不懂的情况下,简单介绍一下 Monaco Editor 的基本使用。由于项目框架是vue2 + webpack,所以基础封装以 vue2 为主。

官网

Monaco Editor 官网

官网的 Playground 可以在线跑 demo,以及提供的了很多功能点的 demo,比较容易理解。

官网的 Documentation 是 api 文档,可以通过快速搜索找到 api 的传参格式样例。

安装

安装monaco-editor

npm install monaco-editoryarn add monaco-editor

安装 monaco-editor-webpack-plugin,是一个用于简化 Monaco Editor 在 Webpack 构建系统中的集成的插件。Monaco Editor 由许多模块和语言特性组成,如果手动管理这些资源可能会非常复杂。使用这个插件,你可以更容易地将 Monaco Editor 集成到你的 Webpack 项目中。

npm install monaco-editor-webpack-pluginyarn add monaco-editor-webpack-pluginwebpack.config.jsconst MonacoWebpackPlugin = require("monaco-editor-webpack-plugin");module.exports = { // ...其他配置 plugins: [new MonacoWebpackPlugin({ languages: ["javascript", "sql"], // 还有很多不同的语言}), ],};

monaco-editor-webpack-plugin 可以配置语言,只对需要的语言进行打包。

monaco-editor-webpack-plugin 的版本要和 monaco editor 匹配。

monaco-editor-webpack-pluginmonaco-editor7.*.*>= 0.31.06.*.*0.30.*5.*.*0.29.*4.*.*0.25.*, 0.26.*, 0.27.*, 0.28.*3.*.*0.22.*, 0.23.*, 0.24.*2.*.*0.21.*1.9.*0.20.*1.8.*0.19.*1.7.*0.18.*组件封装引入monacoimport * as monaco from "monaco-editor";创建Monaco Editor实例this.editor = monaco.editor.create(this.$el, options);监听内容变化更新 (v-model双向绑定)this.editor.onDidChangeModelContent((event) => { const value = this.editor.getValue(); if (this.value !== value) {this.$emit("change", value, event); }});常用的option配置

这里是所有的option配置项,但用上的不是很多而且没有翻译,这里列举一些我使用过的配置项。官方配置项文档

{ fontSize: 16, // 字体大小 automaticLayout: true, // 编辑器自适应页面大小 dropIntoEditor: {enabled: false // 能否把文字拖拽进编辑器 }, value: '初始内容', // 编辑器内容 theme: 'vs' // 主题 'vs-dark', 'hc-black', 'hc-light', language: 'javascript', // 语言 readOnly: true, // 只读 minimap: {enabled: false, // 是否开启右侧代码小窗 }}自定义主题

Monaco Editor 支持自定义主题,官方案例

// 根据语言设置tokenmonaco.languages.setMonarchTokensProvider("自定义语言", {tokenizer: {root: [[/[error.*/, "custom-error"],[/[notice.*/, "custom-notice"],[/[info.*/, "custom-info"],[/[[a-zA-Z 0-9:]+]/, "custom-date"],],},});monaco.editor.defineTheme("自定义主题", {base: "vs",inherit: false,rules: [{ token: "custom-info", foreground: "808080" },{ token: "custom-error", foreground: "ff0000", fontStyle: "bold" },{ token: "custom-notice", foreground: "FFA500" },{ token: "custom-date", foreground: "008800" },],colors: {"editor.foreground": "#000000",},});自定义快捷键,右键菜单

官方案例

editor.addAction({// action唯一的id.id: "my-unique-id",// 右键菜单栏显示的名字.label: "My Label!!!",// 绑定的按键keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.F10,// 组合键monaco.KeyMod.chord(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyK,monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyM),], // 在右键菜单中的哪个分组contextMenuGroupId: "navigation",contextMenuOrder: 1.5, // 触发的方法run: function (ed) {alert("i'm running => " + ed.getPosition());},});代码补全

官方案例

在初始化的时候注册语言的补全提示 registerCompletionItemProvider。语言包关键词可以在node_modules/monaco-editor/esm/vs/basic_languages中找到。

monaco.languages.registerCompletionItemProvider("sql", { provideCompletionItems: async (model, position) => {let suggestions = [];const { lineNumber, column } = position;const textBeforePointer = model.getValueInRange({ startLineNumber: lineNumber, startColumn: 0, endLineNumber: lineNumber, endColumn: column,});/** * 修改suggestion,suggestion就是代码提示 ** 这里可以调用接口,拉去后端提供的提示 */return { suggestions,}; },});插入代码

可以通过 executeEdits 方法插入代码,可以直接替换range内的代码。

range 是代表光标位置的一个对象,可以通过 editor.getPosition() 来获得。也可以通过 editor.getSelection() 来获取选中部分的位置。

editor.executeEdits("", [ {range: range, // 要修改的范围text: code, // 要插入的内容forceMoveMarkers: true, // 是否强制移动光标 },]);高亮部分代码

官方示例

通过 createDecorationsCollection 方法来设置高亮代码,这里也需要一个range对象,来代表高亮的位置。注意,这里高亮是会跟随文字输入移动的,比如说你在高亮范围内换行了,新的一行也会继续高亮。

let decorations = editor.createDecorationsCollection([{range: new monaco.Range(startLine, 1, endLine, 1),options: { isWholeLine: true, className: className,}, },]);// 移除高亮decorations.clear()// 获得高亮的范围decorations.getRanges()插入空行

官方案例

插入空行是指在两行中间增加一行不属于编辑器的一行。copilot就是在输入的过程中,在后面多加几行,实现换行的效果。插入空行并不影响代码内容,一般是用来加个按钮啥的。

let viewZoneId = null;editor.changeViewZones(function (changeAccessor) {let domNode = document.createElement("div");domNode.style.background = "lightgreen";viewZoneId = changeAccessor.addZone({afterLineNumber: 3, // 在哪一行后面增加空行heightInLines: 3, // 空多少行domNode: domNode,});});

changeViewZones 还有 removeZone(viewZoneId) 方法,可以删除空行。

插入额外元素

插入额外元素的demo和上面插入空行的是同一个,先创建一个 contentWidget,然后通过 addContentWidget 方法插入到编辑器中。可以配合插入空行的方法,在编辑器任意位置插入一段话/一个按钮。

var contentWidget = {domNode: (function () {var domNode = document.createElement("div");domNode.innerHTML = "My content widget";return domNode;})(),getId: function () {return "my.content.widget";},getDomNode: function () {return this.domNode;},getPosition: function () {return {position: {lineNumber: 7,column: 8,},preference: [monaco.editor.ContentWidgetPositionPreference.ABOVE,monaco.editor.ContentWidgetPositionPreference.BELOW, // 这里也可以用EXECT, 这样元素会准确的放置在指定行。],};},};editor.addContentWidget(contentWidget);

如果要移除元素,可以通过 editor.removeContentWidget(id) 来将元素移除。

注意,如果元素不在额外空行,而在编辑器内,这个元素是可以选中的,可以调节他的z-index,让他不影响用户使用。

实现一个copilot

掌握上述技巧后,实现一个copilot就非常简单了。

先通过 editor.getPosition() 获取光标位置。editor.getValueInRange() 来获得光标前的内容,然后发送给gpt,获得建议的内容。然后在光标位置用 editor.changeViewZones() 后面插入空行,空行数就是gpt的行数。在光标位置后面用 editor.addContentWidget() 插入元素,内容是gpt的建议内容。增加action,按tab的时候把gpt的建议内容用 executeEdits 替换光标位置的内容。且同时把新增的空行和新增的元素移除。完事

还有一种简单点的方法 基于Monaco Editor实现在线版Copilot

踩坑在组件外更改了内容,不能 ctrl + z 回退咋办?editor.pushUndoStop();// 监听value,通过这个方法更改内容editor.executeEdits("code", [ {range: editor.getModel().getFullModelRange(), // full rangetext: newValue, // target value here },]);editor.pushUndoStop();同一个页面内,不能存在两个 monaco editor, 只能设置同一种主题

Can not create two editor with different theme · Issue #1713 · microsoft/monaco-editor

原文

相关推荐: